﻿using Comm100.Framework.Domain.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Bot.Domain.Entities;
using Bot.Domain.Interfaces;
using Bot.Domain.Bo;
using Castle.Windsor;
using Bot.Domain.Specifications;
using Bot.Domain.BotImport;
using System.Data;
using System.IO;
using Bot.Infrastructure;
using Newtonsoft.Json;
using Bot.Domain.Enum;
using AutoMapper;
using Bot.Domain.Bot;
using System.Text.RegularExpressions;

namespace Bot.Domain.Categories.Service
{
    public class EntityDomainService : IEntityDomainService
    {
        private IWindsorContainer _container;
        private readonly IRepository<Guid, Entity> _repository;
        public IMapper Mapper { get; set; }

        public EntityDomainService(IRepository<Guid, Entity> repository, IWindsorContainer container)
        {
            this._repository = repository;
            this._container = container;
        }

        public Entity Create(Entity entity)
        {
            if(entity.Id == Guid.Empty)
            {
                entity.Id = Guid.NewGuid();
            }
            entity.IsDeleted = false;
            entity.Type = Enum.EnumEntityType.entity;
            IEntityKeywordDomainService keywordsDomainService = _container.Resolve<IEntityKeywordDomainService>();

            if (entity.Keywords != null)
            {
                foreach (var item in entity.Keywords)
                {
                    item.EntityId = entity.Id;
                    item.Id = Guid.NewGuid();
                    keywordsDomainService.Create(item);
                }
            }

            //调用引擎服务
            IBotApiService botApiService = _container.Resolve<IBotApiService>();
            IChatbotDomainService chatbotDomainService = _container.Resolve<IChatbotDomainService>();
            var chatbot = chatbotDomainService.Get(entity.BotId);
            var botDto = Mapper.Map<BotDto>(chatbot);
            var entityDto = Mapper.Map<EntityDto>(entity);
            var mappingToDialogflowId = botApiService.CreateEntity(botDto, entityDto).Result;
            entity.MappingToDialogflowId = mappingToDialogflowId;

            return _repository.Create(entity);            
        }

        public Entity Get(Guid id, string include = "")
        {
            var result = _repository.Get(id);
            if (result != null
                && !string.IsNullOrEmpty(include)
                && include.Split(',').Contains("keywords"))
            {
                IEntityKeywordDomainService keywordsDomainService = _container.Resolve<IEntityKeywordDomainService>();             
                result.Keywords = keywordsDomainService.GetByEntityId(id).ToList();                
            }
            return result;
        }

        public Entity Update(EntityUpdateBo bo)
        {
            Entity entity = _repository.Get(bo.Id);
            //entity.Id = bo.Id;
            //entity.BotId = bo.BotId;
            entity.Name = bo.Name;

            IEntityKeywordDomainService keywordsDomainService = _container.Resolve<IEntityKeywordDomainService>();

            List<Guid> keywordIds = new List<Guid> { };

            foreach (var item in bo.Keywords)
            {
                if (item.Id != Guid.Empty)
                {
                    //修改      
                    item.EntityId = bo.Id;
                    keywordsDomainService.Update(item);
                    keywordIds.Add(item.Id);
                }
                else
                {
                    //新增
                    var keyword = new EntityKeyword();
                    keyword.Id = Guid.NewGuid();
                    item.Id = keyword.Id;
                    keyword.EntityId = bo.Id;
                    item.EntityId = bo.Id;
                    keyword.Content = item.Content;
                    keyword.Synonyms = item.Synonyms;
                    keywordsDomainService.Create(keyword);
                    keywordIds.Add(keyword.Id);
                }
            }
            //删除
            var keywordItems = keywordsDomainService.GetByEntityId(bo.Id);
            foreach (var q in keywordItems)
            {
                if (!keywordIds.Contains(q.Id))
                {
                    keywordsDomainService.Delete(q.Id);
                }
            }

            
            _repository.Update(entity);

            return entity;
        }

        public IEnumerable<Entity> ListCustomEntities(Guid botId, string include = "")
        {
            var list = _repository.List(new EntityFilterSpecification(botId, Enum.EnumEntityType.entity)).ToList();
            if (list != null && list.Count > 0 && !string.IsNullOrEmpty(include) && include.Equals("keywords", StringComparison.OrdinalIgnoreCase))
            {
                IEntityKeywordDomainService keywordsDomainService = _container.Resolve<IEntityKeywordDomainService>();
                foreach (var entity in list)
                {
                    entity.Keywords = keywordsDomainService.GetByEntityId(entity.Id).ToList();
                }
            }
            return list;
        }

        public void Delete(Guid id)
        {
            Entity entity = Get(id, "keywords");
            if (entity.Keywords != null)
            {
                IEntityKeywordDomainService keywordsDomainService = _container.Resolve<IEntityKeywordDomainService>();
                foreach (var keyword in entity.Keywords)
                {
                    keywordsDomainService.Delete(keyword.Id);
                }
            }
            _repository.Delete(entity);

        }

        public List<Entity> GetAllByBotId(Guid botId)
        {
            return _repository.List(new EntityFilterSpecification(botId)).ToList();
        }

        public List<Entity> ListPrebuiltEntities(Guid botId)
        {
            return _repository.List(new EntityFilterSpecification(botId, Enum.EnumEntityType.systemEntity)).ToList();
        }

        public Operation Import(Guid jobId, Chatbot bot, string filePath)
        {
            return new Operation { };
        }

        public bool BatchInsertPrebuiltEntities(int siteId, Guid botId, List<PrebuiltEntity> prebuiltEntities)
        {
            if (prebuiltEntities != null)
            {
                foreach(var prebuiltEntity in prebuiltEntities)
                {
                    var entity = Mapper.Map<Entity>(prebuiltEntity);
                    entity.IsDeleted = false;
                    entity.BotId = botId;
                    entity.Id = Guid.NewGuid();
                    Create(entity);
                }
            }

            return true;
        }

        #region 导入业务逻辑
        public ImportResult ImportEntityAsync(Guid jobId, string filePath, Chatbot bot)
        {
            string xmlFilePath = filePath;

            EnumImportHandleStatus handleStatus = EnumImportHandleStatus.Busy;
            IList<string> errorMessages = new List<string>();

            BackgroundJob backgroundJob = null;
            EntityImportDataQueue entityImportDataQueue = GetImportDataQueue(jobId, xmlFilePath, bot, out backgroundJob);
            try
            {
                if (entityImportDataQueue.ProcessState == EnumOperationStatus.Occupy)
                {
                    //线程处理中
                    handleStatus = EnumImportHandleStatus.Busy;
                }
                else
                {
                    switch (entityImportDataQueue.Status)
                    {
                        case EnumImportHandleStatus.Wait:
                            {
                                entityImportDataQueue.ProcessId = 1;
                                string errorMessage = "";
                                List<EntityImportDto> entityImportDtoList = null;
                                errorMessage = handleFile(filePath, bot, out entityImportDtoList);
                                if (!string.IsNullOrEmpty(errorMessage))
                                {
                                    //存在错误
                                    entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                    errorMessages.Add(errorMessage);
                                    entityImportDataQueue.ErrorMessages = errorMessages;
                                    entityImportDataQueue.ErrorCode = 52226;
                                    string message = APIHelper.GetErrorMessageByCode(entityImportDataQueue.ErrorCode)?.Message;
                                    if (!string.IsNullOrEmpty(message))
                                    {
                                        message = string.Format(message, string.Join(",", errorMessages));
                                        entityImportDataQueue.ErrorMessages = new string[] { message };
                                    }
                                }
                                else
                                {
                                    entityImportDataQueue.Status = EnumImportHandleStatus.CheckData;
                                    entityImportDataQueue.EntityImportDtoList = entityImportDtoList;
                                }
                                break;
                            }
                        //case EnumImportHandleStatus.CheckData:
                        //    {
                        //        entityImportDataQueue.ProcessId = 2;
                        //        string errorMessage = "";
                        //        ApiResult apiResult = await DeleteEngineInfo(botDto);
                        //        if (!apiResult.IsSuccess)
                        //        {
                        //            //存在错误
                        //            errorMessage = apiResult.Error.Message;
                        //            entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                        //            errorMessages.Add(errorMessage);
                        //            entityImportDataQueue.ErrorMessages = errorMessages;
                        //        }
                        //        else
                        //        {
                        //            if (apiResult.Data != null)
                        //            {
                        //                entityImportDataQueue.Status = EnumImportHandleStatus.DeleteEngineInfoProceeing;
                        //                entityImportDataQueue.OperationName = apiResult.Data.ToString();
                        //            }
                        //            else
                        //            {
                        //                entityImportDataQueue.Status = EnumImportHandleStatus.DeleteEngineInfoCompleted;
                        //            }
                        //        }                                
                        //        break;
                        //    }
                        //case EnumImportHandleStatus.DeleteEngineInfoProceeing:
                        //    {
                        //        entityImportDataQueue.ProcessId = 2;
                        //        string errorMessage = "";

                        //        int siteId = botDto.SiteId;
                        //        Guid botId = botDto.Id;
                        //        string name = entityImportDataQueue.OperationName;
                        //        ApiResult apiResult = await botApiService.GetOperations(siteId, botId, name);

                        //        if (!apiResult.IsSuccess)
                        //        {
                        //            //存在错误
                        //            errorMessage = apiResult.Error.Message;
                        //            entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                        //            errorMessages.Add(errorMessage);
                        //            entityImportDataQueue.ErrorMessages = errorMessages;
                        //        }
                        //        else
                        //        {
                        //            if (apiResult.Data != null)
                        //            {
                        //                entityImportDataQueue.Status = EnumImportHandleStatus.DeleteEngineInfoProceeing;
                        //                entityImportDataQueue.OperationName = apiResult.Data.ToString();
                        //            }
                        //            else
                        //            {
                        //                entityImportDataQueue.Status = EnumImportHandleStatus.DeleteEngineInfoCompleted;
                        //            }
                        //        }

                        //        break;
                        //    }
                        //case EnumImportHandleStatus.DeleteEngineInfoCompleted:
                        //    {
                        //        entityImportDataQueue.ProcessId = 3;
                        //        string errorMessage = "";
                        //        errorMessage = DeleteBotEntity(botDto);                            
                        //        if (!string.IsNullOrEmpty(errorMessage))
                        //        {
                        //            //存在错误
                        //            entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                        //            errorMessages.Add(errorMessage);
                        //        }
                        //        else
                        //        {
                        //            entityImportDataQueue.Status = EnumImportHandleStatus.DeleteBotInfo;
                        //        }
                        //        break;
                        //    }
                        case EnumImportHandleStatus.CheckData:
                            {
                                entityImportDataQueue.ProcessId = 2;
                                string errorMessage = "";
                                ApiResult apiResult = ImportEntityByEngine(entityImportDataQueue, bot);

                                if (!apiResult.IsSuccess)
                                {
                                    //存在错误
                                    errorMessage = apiResult.Error.Message;
                                    entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                    errorMessages.Add(errorMessage);
                                    entityImportDataQueue.ErrorMessages = errorMessages;
                                    entityImportDataQueue.ErrorCode = 52227;
                                }
                                else
                                {
                                    if (apiResult.Data != null)
                                    {
                                        entityImportDataQueue.Status = EnumImportHandleStatus.BotEngineImportProceeing;
                                        entityImportDataQueue.OperationName = apiResult.Data.ToString();
                                    }
                                    else
                                    {
                                        entityImportDataQueue.Status = EnumImportHandleStatus.BotEngineImportCompleted;
                                    }
                                }
                                break;
                            }
                        case EnumImportHandleStatus.BotEngineImportProceeing:
                            {
                                entityImportDataQueue.ProcessId = 2;
                                string errorMessage = "";

                                int siteId = bot.SiteId;
                                Guid botId = bot.Id;
                                string name = entityImportDataQueue.OperationName;
                                IBotApiService botApiService = _container.Resolve<IBotApiService>();
                                var botDto = Mapper.Map<BotDto>(bot);
                                ApiResult apiResult = botApiService.GetOperations(botDto, name).Result;

                                if (!apiResult.IsSuccess)
                                {
                                    //存在错误
                                    errorMessage = apiResult.Error.Message;
                                    entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                    errorMessages.Add(errorMessage);
                                    entityImportDataQueue.ErrorCode = 52228;
                                }
                                else
                                {
                                    if (apiResult.Data != null)
                                    {
                                        entityImportDataQueue.Status = EnumImportHandleStatus.BotEngineImportProceeing;
                                        entityImportDataQueue.OperationName = apiResult.Data.ToString();
                                    }
                                    else
                                    {
                                        entityImportDataQueue.Status = EnumImportHandleStatus.BotEngineImportCompleted;
                                    }
                                }
                                break;
                            }
                        case EnumImportHandleStatus.BotEngineImportCompleted:
                            {
                                entityImportDataQueue.ProcessId = 3;
                                string errorMessage = InitDataWithBotEngine(entityImportDataQueue, bot);
                                if (!string.IsNullOrEmpty(errorMessage))
                                {
                                    //存在错误
                                    entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                    errorMessages.Add(errorMessage);
                                    entityImportDataQueue.ErrorCode = 52229;
                                }
                                else
                                {
                                    entityImportDataQueue.Status = EnumImportHandleStatus.InitDataWithBotEngine;
                                }

                                break;
                            }
                        case EnumImportHandleStatus.InitDataWithBotEngine:
                            {
                                entityImportDataQueue.ProcessId = 4;
                                //数据队列化 ,缓存到内存中
                                string errorMessage = ImportData2Queue(entityImportDataQueue);
                                if (!string.IsNullOrEmpty(errorMessage))
                                {
                                    //存在错误
                                    entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                    errorMessages.Add(errorMessage);
                                    entityImportDataQueue.ErrorCode = 52230;
                                }
                                else
                                {
                                    entityImportDataQueue.Status = EnumImportHandleStatus.ImportData2Queue;
                                }

                                break;
                            }
                        case EnumImportHandleStatus.ImportData2Queue:
                        case EnumImportHandleStatus.Processing:
                            {
                                entityImportDataQueue.ProcessId = 5;
                                string errorMessage = SaveDbForImportData(entityImportDataQueue, bot);
                                if (!string.IsNullOrEmpty(errorMessage))
                                {
                                    //存在错误
                                    entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                    errorMessages.Add(errorMessage);
                                    entityImportDataQueue.ErrorCode = 52231;
                                }

                                break;
                            }
                        case EnumImportHandleStatus.Publish:
                            {
                                entityImportDataQueue.ProcessId = 6;
                                string errorMessage = string.Empty;
                                //errorMessage = await PublishBot(appId, versionId, botId, luis);
                                int siteId = bot.SiteId;
                                string operationId = entityImportDataQueue.OperationId;
                                ApiResult apiResult = GetErrorImportExcelPath(entityImportDataQueue.FileName, entityImportDataQueue.EntityImportDtoList, siteId, jobId);

                                if (apiResult.IsSuccess)
                                {
                                    if (apiResult.Data != null && !string.IsNullOrEmpty(apiResult.Data.ToString()))
                                    {
                                        entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                        entityImportDataQueue.FailedPath = apiResult.Data.ToString();
                                    }
                                    else
                                    {
                                        entityImportDataQueue.Status = EnumImportHandleStatus.Succeeded;
                                    }
                                }
                                else
                                {
                                    errorMessage = apiResult.Error.Message;
                                    entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                                    errorMessages.Add(errorMessage);
                                    entityImportDataQueue.ErrorMessages = errorMessages;
                                    entityImportDataQueue.ErrorCode = 52232;
                                }
                                break;
                            }
                        default:
                            break;
                    }

                    handleStatus = entityImportDataQueue.Status;
                }
            }
            catch (Exception e)
            {
                errorMessages.Add(e.Message);
                entityImportDataQueue.ErrorMessages.Add(e.Message);
                LogHelper.Error(JsonConvert.SerializeObject(e));
                entityImportDataQueue.Status = EnumImportHandleStatus.Failed;
                handleStatus = EnumImportHandleStatus.Failed;
            }
            finally
            {
                if (entityImportDataQueue.ProcessState == EnumOperationStatus.Free)
                {
                    entityImportDataQueue.ProcessState = EnumOperationStatus.Free;
                    SetImportDataQueue(jobId, filePath, entityImportDataQueue, bot, backgroundJob);
                }
            }

            if (handleStatus == EnumImportHandleStatus.Failed)
            {//为了让下一次调用接口时候，返回上次的错误消息
                errorMessages = entityImportDataQueue.ErrorMessages;

                //LogHelper.Error(JsonConvert.SerializeObject(new
                //{
                //    Processed = entityImportDataQueue.ProcessId,
                //    Status = handleStatus.ToString(),
                //    ErrorMessage = string.Join(",", errorMessages)
                //}));
            }

            return new ImportResult
            {
                Processed = entityImportDataQueue.ProcessId,
                Total = 6,
                Status = handleStatus,
                ErrorMessage = string.Join(",", errorMessages),
                FailUrl = entityImportDataQueue.FailedPath,
                OperationId = entityImportDataQueue.OperationId,
                ErrorCode = entityImportDataQueue.ErrorCode,
            };
        }

        private string handleFile(string filePath, Chatbot bot, out List<EntityImportDto> entityImportDtoList)
        {
            IEntityDomainService entityDomainService = _container.Resolve<IEntityDomainService>();
            IEntityKeywordDomainService entityKeywordDomainService = _container.Resolve<IEntityKeywordDomainService>();

            entityImportDtoList = new List<EntityImportDto>();

            DataTable dataTable = null;
            string errorMsg = CheckFile(filePath, out dataTable);
            if (!string.IsNullOrEmpty(errorMsg))
            {
                return errorMsg;
            }

            if (dataTable != null && dataTable.Rows.Count > 0)
            {
                if (!dataTable.Columns.Contains("Entity Name"))
                    return "Column [Entity Name] is required.";
                if (!dataTable.Columns.Contains("Keyword"))
                    return "Column [Keyword] is required.";
                if (!dataTable.Columns.Contains("Synonyms"))
                    return "Column [Synonyms] is required.";

                foreach (DataRow row in dataTable.Rows)
                {
                    if (string.IsNullOrWhiteSpace(row["Entity Name"].ToString()) && string.IsNullOrWhiteSpace(row["Keyword"].ToString()) && string.IsNullOrWhiteSpace(row["Synonyms"].ToString()))
                        continue;
                    string entityName = row["Entity Name"].ToString();
                    string keyword = row["Keyword"].ToString().Trim();
                    string synonyms = row["Synonyms"].ToString();
                    string errMsg = row.Table.Columns.Contains("Error Message") ? row["Error Message"].ToString() : "";

                    if (string.IsNullOrEmpty(errMsg))
                    {
                        if (string.IsNullOrEmpty(entityName))
                        {
                            errMsg += string.Format("{0} is required.", "Entity Name");
                        }
                        else
                        {
                            //if (!NameCheck(bot.SiteId, bot.Id, 0, entityName))
                            //{
                            //    errMsg += string.Format("Entity with the same name already exists.");
                            //}

                            if (entityName.Trim().ToLower() == "default")
                            {
                                errMsg += string.Format("Entity name cannot be default.");
                            }
                            else if (Encoding.UTF8.GetByteCount(entityName) > 30)
                            {
                                errMsg += string.Format("The length of entity name  should be less than 31.");
                            }
                            else
                            {
                                if (!Regex.IsMatch(entityName, @"^(?![0-9_-])[a-zA-Z0-9_-]*[a-zA-Z0-9]{1,30}$"))
                                {
                                    errMsg += string.Format("Entity name may contain only the following:A-Z,a-z,0-9,_,-.And it should start with a letter.And it can't end by _.");
                                }
                            }
                        }

                        if (string.IsNullOrEmpty(keyword))
                        {
                            errMsg += string.Format("{0} is required.", "keyword");
                        }
                    }

                    List<string> listSynonyms = string.IsNullOrWhiteSpace(synonyms) ? new List<string>() : synonyms.Replace('|', ',').Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();

                    if (!listSynonyms.Contains(keyword))
                    {
                        listSynonyms.Add(keyword);
                        if (string.IsNullOrEmpty(synonyms))
                        {
                            synonyms = string.Format("{0}", keyword);
                        }
                        else
                        {
                            synonyms += string.Format("|{0}", keyword);
                        }
                    }

                    listSynonyms = string.IsNullOrWhiteSpace(synonyms) ? new List<string>() : synonyms.Replace('|', ',').Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();

                    if (!string.IsNullOrEmpty(keyword) && Encoding.UTF8.GetByteCount(keyword) > 128)
                    {
                        errMsg += string.Format("The length of {0} should be less than 129.", "keyword");
                    }
                    if (!string.IsNullOrEmpty(keyword) && !CheckKeyword_SynonymsValidation(keyword))
                    {
                        errMsg += "Keyword cannot include \\,<,>,^,(,),|;cannot begin with @ or _;cannot end with _;{},[],\"\" should be only appear in pairs and cannot be empty.";
                    }
                    if (!string.IsNullOrEmpty(synonyms) && synonyms.Trim().StartsWith("@"))
                    {
                        errMsg += string.Format("The {0} should not start with @.", "synonyms");
                    }
                    if (!string.IsNullOrEmpty(synonyms) && Encoding.UTF8.GetByteCount(synonyms) > 4000)
                    {
                        errMsg += string.Format("The total length of {0} should be less than 4001.", "synonyms");
                    }

                    listSynonyms = listSynonyms.Distinct().ToList();

                    if (listSynonyms == null || listSynonyms.Count == 0)
                    {
                        errMsg += string.Format("The {0} item should not be empty.", "synonyms");
                    }
                    else
                    {
                        if (listSynonyms.Where(m => Encoding.UTF8.GetByteCount(m) > 128).Count() > 0)
                        {
                            errMsg += string.Format("The length of any {0} item should be less than 129.", "synonyms");
                        }
                    }

                    listSynonyms.ForEach(delegate (string synonym) {
                        if (!CheckKeyword_SynonymsValidation(synonym))
                        {
                            errMsg += "Synonyms cannot include \\,<,>,^,(,),|;cannot begin with @ or _;cannot end with _;{},[],\"\" should be only appear in pairs and cannot be empty.";
                        }
                    });
                    EntityImportDto entityImportDto = new EntityImportDto()
                    {
                        EntityName = entityName,
                        Keyword = keyword,
                        Synonyms = string.Join("|", listSynonyms.ToArray()),
                        ErrorMsg = errMsg
                    };

                    entityImportDtoList.Add(entityImportDto);
                }

                if (entityImportDtoList.Any(a => string.IsNullOrEmpty(a.ErrorMsg)))
                {
                    //存在需要导入的数据
                    var botEntityList = entityDomainService.GetAllByBotId(bot.Id);
                    var botEntityNoSystemList = botEntityList.Where(a => a.Type == EnumEntityType.entity).ToList();
                    //新增加的Entity
                    var entityImportDtoInsertList =
                        from entity in entityImportDtoList
                        where !botEntityNoSystemList.Exists(a => a.Name == entity.EntityName)
                        select entity;
                    var entityImportDtoInsertDistinctList = entityImportDtoInsertList.DistinctBy(a => a.EntityName);
                    if (botEntityNoSystemList.Count() + entityImportDtoInsertDistinctList.Count() > 249)
                    {
                        errorMsg = APIHelper.GetErrorMessageByCode(52243).Message;
                    }
                }
            }
            else
                errorMsg = "No data to import";
            return errorMsg;
        }
        int SubstringCount(string originalString, string subString)
        {
            string strReplaced = originalString.Replace(subString, "");
            return (originalString.Length - strReplaced.Length) / subString.Length;
        }
        bool CheckKeyword_SynonymsValidation(string value)
        {
            if (!string.IsNullOrWhiteSpace(value))
            {
                if (value.IndexOfAny(new char[] { '\\', '<', '>', '^', '(', ')', '|' }) > -1)
                    return false;
                if (value.Trim().Substring(0, 1).IndexOfAny(new char[] { '@', '_' }) > -1 || value.Trim().EndsWith("_"))
                    return false;
                if (!(value.IndexOf('{') > -1 & value.IndexOf('}') > -1) && !(value.IndexOf('{') < 0 && value.IndexOf('}') < 0))
                    return false;
                if (!(value.IndexOf('[') > -1 & value.IndexOf(']') > -1) && !(value.IndexOf('[') < 0 && value.IndexOf(']') < 0))
                    return false;
                if (value.IndexOf('{') > -1 && value.IndexOf('}') > -1 && Math.Abs(value.IndexOf('{') - value.IndexOf('}')) == 1)
                    return false;
                if (value.IndexOf('[') > -1 && value.IndexOf(']') > -1 && Math.Abs(value.IndexOf('[') - value.IndexOf(']')) == 1)
                    return false;
                if (value.IndexOf('"') > -1 && SubstringCount(value.Trim(), "\"") % 2 == 1)
                    return false;

                return true;
            }

            return false;
        }

        private string CheckFile(string filePath, out DataTable dataTable)
        {
            string errorMsg = "";
            dataTable = null;

            string[] fileExtensions = new string[] { ".xls", ".xlsx", ".csv" };
            if (File.Exists(filePath))
            {
                FileInfo fileInfo = new FileInfo(filePath);
                string extension = fileInfo.Extension;
                decimal fileSize = Math.Round(decimal.Divide(fileInfo.Length, 1024), 2);

                if (!fileExtensions.Contains(extension))
                {
                    errorMsg = "Invalid file type.";
                }
                else if (fileSize > 100)
                {
                    errorMsg = "The file size should be less than 100KB.";
                }
                else
                {

                    var util = TransferDataFactory.GetUtil(filePath);

                    try
                    {
                        dataTable = util.GetData(filePath);
                    }
                    catch (Exception e)
                    {
                        errorMsg = "Invalid file.";
                    }

                    if (dataTable != null && dataTable.Rows.Count > 50)
                    {
                        errorMsg = "You can only import 50 Entities at a time.";
                    }
                    else
                    {

                    }
                }
            }
            else
            {
                errorMsg = "File not exist";
            }

            return errorMsg;
        }
        private ApiResult ImportEntityByEngine(EntityImportDataQueue entityImportDataQueue, Chatbot bot)
        {
            ApiResult apiResult = new ApiResult { IsSuccess = true };
            try
            {
                IEntityDomainService entityDomainService = _container.Resolve<IEntityDomainService>();
                IEntityKeywordDomainService entityKeywordDomainService = _container.Resolve<IEntityKeywordDomainService>();
                IBotApiService botApiService = _container.Resolve<IBotApiService>();

                List<BotEntityTypeEx> botEntityTypeExList = new List<BotEntityTypeEx>();
                if (entityImportDataQueue.EntityImportDtoList != null && entityImportDataQueue.EntityImportDtoList.Count > 0)
                {
                    //所有的Entity
                    var botEntitiesList = entityDomainService.GetAllByBotId(bot.Id);
                    var listEntityItemsList = entityKeywordDomainService.GetByBotId(bot.Id);

                    //只处理没有错误的数据
                    List<EntityImportDto> noErrorEntityImportDto = entityImportDataQueue.EntityImportDtoList.Where(a => a.ErrorMsg.Length == 0).ToList();
                    //分组
                    var noErrorEntityImportDtoGroupList = noErrorEntityImportDto.GroupBy(key => key.EntityName);
                    foreach (IGrouping<string, EntityImportDto> noErrorEntityGroup in noErrorEntityImportDtoGroupList)
                    {
                        BotEntityTypeEx botEntityTypeEx = null;
                        List<BotListEntityItemTypeEx> botListEntityItemTypeExList = null;

                        var botEntities = botEntitiesList.FirstOrDefault(a => a.Name == noErrorEntityGroup.Key);
                        if (botEntities != null && botEntities.Id != Guid.Empty)
                        {
                            //已经存在的Entity
                            botEntityTypeEx = botEntityTypeExList.FirstOrDefault(a => a.EntityName == noErrorEntityGroup.Key);
                            if (botEntityTypeEx == null)
                            {
                                //先把数据库中的数据加载
                                //存储Entity
                                var listEntityItemsFind = listEntityItemsList.Where(a => a.EntityId == botEntities.Id).ToList();
                                botListEntityItemTypeExList = new List<BotListEntityItemTypeEx>();
                                foreach (var listEntityItems in listEntityItemsFind)
                                {
                                    botListEntityItemTypeExList.Add(new BotListEntityItemTypeEx
                                    {
                                        KeyWord = listEntityItems.Content,
                                        SynonymsOfKeyWord = listEntityItems.Synonyms
                                    });
                                }

                                botEntityTypeExList.Add(new BotEntityTypeEx
                                {
                                    EntityName = noErrorEntityGroup.Key,
                                    EntityItem = botListEntityItemTypeExList.ToArray()
                                });

                            }

                        }
                        else
                        {
                            //不存在的Entity
                            botEntityTypeExList.Add(new BotEntityTypeEx
                            {
                                EntityName = noErrorEntityGroup.Key,
                                EntityItem = new BotListEntityItemTypeEx[] { }
                            });
                        }

                        botEntityTypeEx = botEntityTypeExList.FirstOrDefault(a => a.EntityName == noErrorEntityGroup.Key);

                        botListEntityItemTypeExList = botEntityTypeEx.EntityItem.ToList();

                        foreach (EntityImportDto entityImportDto in noErrorEntityGroup)
                        {
                            BotListEntityItemTypeEx botListEntityItemTypeEx = botListEntityItemTypeExList.FirstOrDefault(a => a.KeyWord == entityImportDto.Keyword);
                            if (botListEntityItemTypeEx != null)
                            {
                                //
                                string[] synonymsOfKeyWordArray = entityImportDto.Synonyms.Replace('|', ',').Split(',');
                                foreach (string synonymsOfKeyWord in synonymsOfKeyWordArray)
                                {
                                    if (!botListEntityItemTypeEx.SynonymsOfKeyWord.Contains(synonymsOfKeyWord))
                                    {
                                        if (string.IsNullOrEmpty(botListEntityItemTypeEx.SynonymsOfKeyWord))
                                        {
                                            botListEntityItemTypeEx.SynonymsOfKeyWord += string.Format("{0}", synonymsOfKeyWord);
                                        }
                                        else
                                        {
                                            botListEntityItemTypeEx.SynonymsOfKeyWord += string.Format(",{0}", synonymsOfKeyWord);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                botListEntityItemTypeExList.Add(new BotListEntityItemTypeEx
                                {
                                    KeyWord = entityImportDto.Keyword,
                                    SynonymsOfKeyWord = entityImportDto.Synonyms.Replace('|', ',')
                                });
                            }
                        }

                        botEntityTypeEx.EntityItem = botListEntityItemTypeExList.ToArray();

                    }

                    if (botEntityTypeExList.Count > 0)
                    {
                        BotImportDataQueue botImportDataQueue = new BotImportDataQueue
                        {
                            SiteId = bot.SiteId,
                            BotId = bot.Id,
                            AppId = bot.DialogFlowProjectId,
                            OperateType = EnumOperateType.importEntity,
                            BotImportData = new BotImportDataEx
                            {
                                Bot = new BotTypeEx
                                {
                                    Language = bot.Language,
                                    Entity = botEntityTypeExList.ToArray()
                                }
                            }
                        };
                        var botDto = Mapper.Map<BotDto>(bot);
                        apiResult = botApiService.ImportBot(botDto,botImportDataQueue).Result;
                    }
                }
            }
            catch (Exception e)
            {
                apiResult.IsSuccess = false;
                apiResult.Error = new ErrorInfo
                {
                    Message = e.Message
                };
                LogHelper.Error(JsonConvert.SerializeObject(e));
            }
            finally
            {

            }
            return apiResult;
        }

        private string InitDataWithBotEngine(EntityImportDataQueue entityImportDataQueue, Chatbot bot)
        {
            string errorMessage = "";
            try
            {
                IBotApiService botApiService = _container.Resolve<IBotApiService>();
                //从luis取出intent，entity数据将id的值设置到对应的数据中，以便数据库存储
                var botDto = Mapper.Map<BotDto>(bot);
                List<EntityModelAggregate> entityModelAggregateList = botApiService.GetEntityList(botDto).Result;
                SetEntityIdForBotImportData(entityModelAggregateList, entityImportDataQueue, bot);
            }
            catch (Exception e)
            {
                errorMessage = e.Message;
                LogHelper.Error(JsonConvert.SerializeObject(e));
            }
            finally
            {

            }
            return errorMessage;

        }
        private void SetEntityIdForBotImportData(List<EntityModelAggregate> entityModelAggregateList, EntityImportDataQueue entityImportDataQueue, Chatbot bot)
        {
            //只处理没有错误的数据
            List<EntityImportDto> noErrorEntityImportDto = entityImportDataQueue.EntityImportDtoList.Where(a => a.ErrorMsg.Length == 0).ToList();

            if (entityModelAggregateList != null && entityModelAggregateList.Count > 0)
            {
                foreach (EntityImportDto entityImportDto in noErrorEntityImportDto)
                {
                    string entityId = entityModelAggregateList.FirstOrDefault(a => a.EntityModel.EntityName == entityImportDto.EntityName)?.EntityModel.Id;
#if DEBUG
                    entityId = Guid.NewGuid().ToString();
#endif

                    if (bot.EngineType == EnumBotType.comm100OwnBot)
                    {//2019.6.20 comm100OwnBot
                        entityId = Guid.NewGuid().ToString();
                    }

                    if (!string.IsNullOrEmpty(entityId))
                    {
                        entityImportDto.Id = string.Format("{0}", entityId);
                    }
                    else
                    {
                        entityImportDto.ErrorMsg = string.Format("Cannot find an application version with the version.");
                    }

                }
            }
            else
            {
                foreach (EntityImportDto entityImportDto in noErrorEntityImportDto)
                {
                    entityImportDto.ErrorMsg = string.Format("Cannot find an application version with the version.");
                }
            }
        }

        private EntityImportDataQueue GetImportDataQueue(Guid jobId, string fileName, Chatbot bot, out BackgroundJob backgroundJob)
        {
            IBackgroundJobDomainService backgroundJobDomainService = _container.Resolve<IBackgroundJobDomainService>();
            backgroundJob = null;

            //EntityImportDataQueue entityImportDataQueue = Utils.GetMemoryCache<EntityImportDataQueue>(key);
            EntityImportDataQueue entityImportDataQueue = null;
            backgroundJob = backgroundJobDomainService.Get(jobId);

            //string key = jobId.ToString();
            //backgroundJob = Utils.GetMemoryCache<BackgroundJob>(key);

            if (backgroundJob != null)
            {
                entityImportDataQueue = JsonConvert.DeserializeObject<EntityImportDataQueue>(backgroundJob.Content);
            }

            if (entityImportDataQueue == null)
            {
                entityImportDataQueue = new EntityImportDataQueue()
                {
                    ProcessState = EnumOperationStatus.Free,
                    FileName = fileName
                };

                EntityImportDataQueue newEntityImportDataQueue = new EntityImportDataQueue(entityImportDataQueue);
                newEntityImportDataQueue.ProcessState = EnumOperationStatus.Occupy;
                backgroundJob = CreateImportDataQueue(jobId, fileName, newEntityImportDataQueue, bot);

                entityImportDataQueue.OperationId = jobId.ToString();
            }
            else if (entityImportDataQueue.ProcessState == EnumOperationStatus.Free)
            {
                EntityImportDataQueue newEntityImportDataQueue = new EntityImportDataQueue(entityImportDataQueue);
                newEntityImportDataQueue.ProcessState = EnumOperationStatus.Occupy;
                SetImportDataQueue(jobId, fileName, newEntityImportDataQueue, bot, backgroundJob);
            }
            return entityImportDataQueue;
        }
        private BackgroundJob CreateImportDataQueue(Guid jobId, string fileName, EntityImportDataQueue entityImportDataQueue, Chatbot bot)
        {
            OperateEntity operateEntity = new OperateEntity
            {
                SiteId = bot.SiteId,
                BotId = bot.Id,
                FilePath = fileName,
                OperateType = EnumOperateType.importEntity,
                Content = entityImportDataQueue,
            };
            BackgroundJob job = new BackgroundJob
            {
                Id = jobId,
                SiteId = bot.SiteId,
                BotId = bot.Id,
                Type = EnumOperateType.importEntity,
                Attachment = new byte[] { },
                Content = JsonConvert.SerializeObject(operateEntity),
                Status = entityImportDataQueue.ProcessState,
                CreatedTime = DateTime.UtcNow,
            };
            //string key = jobId.ToString();
            //Utils.SetMemoryCache(key, job);
            IBackgroundJobDomainService backgroundJobDomainService = _container.Resolve<IBackgroundJobDomainService>();
            backgroundJobDomainService.Create(job);

            return job;
        }
        private void SetImportDataQueue(Guid jobId, string fileName, EntityImportDataQueue entityImportDataQueue, Chatbot bot, BackgroundJob backgroundJob)
        {
            OperateEntity operateEntity = new OperateEntity
            {
                SiteId = bot.SiteId,
                BotId = bot.Id,
                FilePath = fileName,
                OperateType = EnumOperateType.importEntity,
                Content = entityImportDataQueue,
            };
            BackgroundJobUpdateBo job = new BackgroundJobUpdateBo
            {
                Id = jobId,
                SiteId = bot.SiteId,
                BotId = bot.Id,
                Type = EnumOperateType.importEntity,
                Attachment = new byte[] { },
                Content = JsonConvert.SerializeObject(operateEntity),
                Status = entityImportDataQueue.ProcessState,
                CreatedTime = DateTime.UtcNow,
            };
            //string key = jobId.ToString();
            //Utils.SetMemoryCache(key, job);
            IBackgroundJobDomainService backgroundJobDomainService = _container.Resolve<IBackgroundJobDomainService>();
            backgroundJobDomainService.Update(job);
        }

        private string ImportData2Queue(EntityImportDataQueue entityImportDataQueue)
        {
            string errorMessage = "";
            try
            {
                //只处理没有错误的数据
                List<EntityImportDto> noErrorEntityImportDto = entityImportDataQueue.EntityImportDtoList.Where(a => a.ErrorMsg.Length == 0).ToList();
                //分组
                var noErrorEntityImportDtoGroupList = noErrorEntityImportDto.GroupBy(key => key.EntityName);
                foreach (IGrouping<string, EntityImportDto> noErrorEntityGroup in noErrorEntityImportDtoGroupList)
                {
                    //存储Entity
                    //Dictionary<string, List<EntityImportDto>> keyValues = new Dictionary<string, List<EntityImportDto>>();
                    //keyValues.Add(noErrorEntityGroup.Key, noErrorEntityGroup.ToList());
                    dynamic data = new
                    {
                        EntityName = noErrorEntityGroup.Key,
                        EntityImportDtos = noErrorEntityGroup.ToList(),
                    };
                    entityImportDataQueue.ImportDataQueue.Enqueue(data);
                }

            }
            catch (Exception e)
            {
                errorMessage = e.Message;
                LogHelper.Error(JsonConvert.SerializeObject(e));
            }
            finally
            {

            }
            return errorMessage;
        }

        private string SaveDbForImportData(EntityImportDataQueue entityImportDataQueue, Chatbot bot)
        {
            string errorMessage = "";
            try
            {
                IEntityDomainService entityDomainService = _container.Resolve<IEntityDomainService>();
                IEntityKeywordDomainService entityKeywordDomainService = _container.Resolve<IEntityKeywordDomainService>();

                //为了前端能够及时收到消息，一次只处理50条
                int index = 0;
                var botEntitiesList = entityDomainService.GetAllByBotId(bot.Id);

                while (entityImportDataQueue.ImportDataQueue.Count > 0)
                {
                    if (index > 50)
                    {
                        break;
                    }
                    else
                    {
                        var data = JsonConvert.DeserializeObject<dynamic>(Convert.ToString(entityImportDataQueue.ImportDataQueue.Dequeue()));

                        if (data != null)
                        {
                            List<EntityImportDto> entityImportDtos = JsonConvert.DeserializeObject<List<EntityImportDto>>(Convert.ToString(data.EntityImportDtos));
                            string entityName = data.EntityName;
                            string mappingToBotEngine = entityImportDtos.FirstOrDefault().Id;

                            //新增 entity
                            //同步到数据库
                            //insert list entity data to database
                            var botEntities = botEntitiesList.FirstOrDefault(a => a.Name == entityName);
                            if (botEntities != null && botEntities.Id != Guid.Empty)
                            {

                            }
                            else
                            {
                                botEntities = new Entity
                                {
                                    Id = Guid.Empty,
                                    BotId = bot.Id,
                                    Name = entityName,
                                    Type = EnumEntityType.entity,
                                    MappingToDialogflowId = mappingToBotEngine,
                                };
                                botEntities = entityDomainService.Create(botEntities);
                            }

                            if (botEntities != null && botEntities.Id != Guid.Empty)
                            {
                                foreach (EntityImportDto entityImportDto in entityImportDtos)
                                {
                                    var listEntityItemsList = entityKeywordDomainService.GetByEntityId(botEntities.Id);
                                    var listEntityItems = listEntityItemsList.FirstOrDefault(a => a.Content == entityImportDto.Keyword);
                                    if (listEntityItems != null && listEntityItems.Id != Guid.Empty)
                                    {
                                        //keyword 已经存在
                                        //存储SynonymsOfKeyWord 变更内容
                                        string synonymsOfKeyWord = entityImportDto.Synonyms?.Replace('|', ',');
                                        string[] synonymsOfKeyWordArray = synonymsOfKeyWord.Split(',');
                                        foreach (string synonyms in synonymsOfKeyWordArray)
                                        {
                                            if (!listEntityItems.SynonymList.Contains(synonyms))
                                            {
                                                if (string.IsNullOrEmpty(listEntityItems.Synonyms))
                                                {
                                                    listEntityItems.Synonyms = JsonConvert.SerializeObject(new List<string> { synonyms });
                                                }
                                                else
                                                {
                                                    listEntityItems.Synonyms = JsonConvert.SerializeObject(listEntityItems.SynonymList.Concat(new List<string> { synonyms }));
                                                }
                                            }
                                        }
                                        var keywordBo = new EntityKeywordUpdateBo {
                                            Id = listEntityItems.Id,
                                            EntityId = listEntityItems.EntityId,
                                            Content = listEntityItems.Content,
                                            Synonyms = listEntityItems.Synonyms,
                                        };
                                        entityKeywordDomainService.Update(keywordBo);
                                    }
                                    else
                                    {
                                        listEntityItems = new EntityKeyword
                                        {
                                            Id = Guid.NewGuid(),
                                            EntityId = botEntities.Id,                                            
                                            Content = entityImportDto.Keyword,
                                            Synonyms = JsonConvert.SerializeObject( entityImportDto.Synonyms?.Split('|')),
                                        };
                                        listEntityItems = entityKeywordDomainService.Create(listEntityItems);
                                    }

                                    if (listEntityItems != null && listEntityItems.Id != Guid.Empty)
                                    {
                                        entityImportDto.ErrorMsg = "success";
                                    }
                                    else
                                    {
                                        entityImportDto.ErrorMsg = "insert list entity sublist to database fail";
                                    }
                                }
                            }
                            else
                            {
                                foreach (EntityImportDto entityImportDto in data.EntityImportDtos)
                                {
                                    entityImportDto.ErrorMsg = "insert entity to database fail";
                                }

                            }
                        }
                        index++;
                    }
                }

                if (entityImportDataQueue.ImportDataQueue.Count == 0)
                {
                    entityImportDataQueue.Status = EnumImportHandleStatus.Publish;
                }
                else
                {
                    entityImportDataQueue.Status = EnumImportHandleStatus.Processing;
                }
            }
            catch (Exception e)
            {
                LogHelper.Error(JsonConvert.SerializeObject(e));
                errorMessage = e.Message;
            }
            finally
            {

            }

            return errorMessage;
        }

        private ApiResult GetErrorImportExcelPath(string filePath, List<EntityImportDto> entityImportDtoList, int siteId, Guid jobId)
        {
            ApiResult apiReuslt = new ApiResult { IsSuccess = false };
            try
            {
                string[] arr = filePath.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
                string fileName = string.Format("Failed {0}", arr.LastOrDefault());

                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "UploadedFiles");
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
                if (Directory.Exists(path))
                {
                    path = Path.Combine(path, siteId.ToString());
                    if (!Directory.Exists(path))
                        Directory.CreateDirectory(path);
                    if (Directory.Exists(path))
                    {
                        string serverFileName = Path.Combine(path, fileName);
                        path = serverFileName;
                    }
                }

                //写入存在错误信息的数据到Excel
                DataTable errTable = new DataTable();

                errTable.Columns.Add("Entity Name");
                errTable.Columns.Add("Keyword");
                errTable.Columns.Add("Synonyms");
                errTable.Columns.Add("Error Message");

                bool haveErr = false;

                List<EntityImportDto> errorEntityImportDtoList = entityImportDtoList.Where(a => (a.ErrorMsg.Length > 0 && a.ErrorMsg != "success")).ToList();
                foreach (EntityImportDto entityImportDto in errorEntityImportDtoList)
                {
                    haveErr = true;
                    DataRow newRow = errTable.NewRow();
                    errTable.Rows.Add(newRow);
                    newRow["Entity Name"] = entityImportDto.EntityName;
                    newRow["Keyword"] = entityImportDto.Keyword;
                    newRow["Synonyms"] = entityImportDto.Synonyms;
                    newRow["Error Message"] = entityImportDto.ErrorMsg;
                }
                List<EntityImportDto> successEntityImportDtoList = entityImportDtoList.Where(a => (a.ErrorMsg.Length > 0 && a.ErrorMsg == "success")).ToList();
                foreach (EntityImportDto entityImportDto in successEntityImportDtoList)
                {
                    DataRow newRow = errTable.NewRow();
                    errTable.Rows.Add(newRow);
                    newRow["Entity Name"] = entityImportDto.EntityName;
                    newRow["Keyword"] = entityImportDto.Keyword;
                    newRow["Synonyms"] = entityImportDto.Synonyms;
                    newRow["Error Message"] = "";
                }

                if (haveErr)
                {
                    var util = TransferDataFactory.GetUtil(filePath);
                    util.SaveData(errTable, path);

                    //存储到数据库
                    //IBackgroundJobDomainService backgroundJobDomainService = _container.Resolve<IBackgroundJobDomainService>();
                    //BackgroundJob backgroundJob = backgroundJobDomainService.Get(jobId);
                    //backgroundJob.Attachment = File.ReadAllBytes(path);
                    //BackgroundJobUpdateBo backgroundJobUpdateBo = Mapper.Map<BackgroundJobUpdateBo>(backgroundJob);
                    //backgroundJobDomainService.Update(backgroundJobUpdateBo);

                    //var psi = new System.Diagnostics.ProcessStartInfo("hostname");
                    //return $"{psi.Domain}/api/v3/chatbot/images/{Id}";

                    //strResult = string.Format("{0}/{1}", masterUrl, "api/v2/bot/downloadFile?operationId=" + operationId);
                    //strResult = strResult.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault();
                   
                    apiReuslt.Error = new ErrorInfo
                    {
                        Message = string.Join(",", errorEntityImportDtoList.Select(a => a.ErrorMsg)),
                    };
                }
                apiReuslt.IsSuccess = true;
            }
            catch (Exception e)
            {
                apiReuslt.IsSuccess = false;
                apiReuslt.Error = new ErrorInfo
                {
                    Message = e.Message
                };
                LogHelper.Error(JsonConvert.SerializeObject(e));
            }
            finally
            {

            }

            return apiReuslt;

        }

        /// <summary>
        /// 字符串转小写,去掉多余的空格
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private string TextTrim(string text)
        {
            if (string.IsNullOrWhiteSpace(text))
            {
                return "";
            }
            else
            {
                string[] arry = text.Trim().Replace("\n", "").Replace("\r", "").ToLower().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                text = string.Join(" ", arry);
                return text;
            }
        }
        #endregion
    }
}
